﻿using System;
using System.Xml.Linq;
using NthDownload.Common.Utils;
using NthDownload.Contracts;
using NthDownload.Contracts.Plugins.Downloads;

namespace NthDownload.DownloadPlugins.Http.Serialization
{
    public class HttpDownloadXmlSerializationService : IDownloadXmlSerializationService
    {
        private readonly string _pluginGUID;

        public HttpDownloadXmlSerializationService(string pluginGUID)
        {
            _pluginGUID = pluginGUID;
        }

        public XElement Serialize(IDownload obj)
        {
            HttpDownload download = obj as HttpDownload;

            if (download == null)
            {
                throw new Exception("Unexpected type, recieved '" + obj.GetType() + "' expected '" + typeof(HttpDownload) + "'.");
            }

            //
            // Build XML
            //
            XElement rootElement = new XElement("Data");

            rootElement.SetAttributeValue("GUID", download.GUID);
            rootElement.SetAttributeValue("CanResume", download.CanResume);
            rootElement.SetAttributeValue("CanQueue", download.CanQueue);
            rootElement.SetAttributeValue("HasSize", download.HasSize);
            rootElement.SetAttributeValue("IsInitialized", download.IsInitialized);
            rootElement.SetAttributeValue("Path", download.Path);
            rootElement.SetAttributeValue("DestinationFolder", download.DestinationFolder);
            rootElement.SetAttributeValue("DestinationPath", download.DestinationPath);
            rootElement.SetAttributeValue("Description", download.Description);
            rootElement.SetAttributeValue("Size", download.Size);
            rootElement.SetAttributeValue("FileName", download.FileName);
            rootElement.SetAttributeValue("Position", download.Position);
            rootElement.SetAttributeValue("ChunkSize", download.ChunkSize);
            rootElement.SetAttributeValue("DownloadedAmount", download.DownloadedAmount);
            rootElement.SetAttributeValue("DateCreated", download.DateCreated);
            rootElement.SetAttributeValue("DateCompleted", download.DateCompleted);
            rootElement.SetAttributeValue("TimeElapsed", download.TimeElapsed);
            rootElement.SetAttributeValue("Status", download.Status);

            XElement segmentsElement = new XElement("Segments");
            rootElement.Add(segmentsElement);

            foreach (DownloadSegment downloadSegment in download.Segments)
            {
                XElement segmentElement = new XElement("Segment");

                segmentElement.SetAttributeValue("StartPosition", downloadSegment.StartPosition);
                segmentElement.SetAttributeValue("CurrentPosition", downloadSegment.CurrentPosition);
                segmentElement.SetAttributeValue("EndPosition", downloadSegment.EndPosition);

                segmentsElement.Add(segmentElement);
            }

            return rootElement;
        }

        public IDownload Deserialize(XElement data)
        {
            HttpDownload download = new HttpDownload("");
            Deserialize(data, download);

            return download;
        }

        public void Deserialize(XElement data, IDownload obj)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            if (obj == null)
            {
                throw new ArgumentNullException("obj");
            }

            HttpDownload download = obj as HttpDownload;

            if (download == null)
            {
                throw new Exception("'" + typeof(HttpDownload) + "' expected '" + obj.GetType() + "' recieved when attempting to deserialize download." );
            }

            download.GUID = (string)data.Attribute("GUID") ?? "";
            download.CanResume = (bool?)data.Attribute("CanResume") ?? true;
            download.CanQueue = (bool?)data.Attribute("CanQueue") ?? true;
            download.HasSize = (bool?)data.Attribute("HasSize") ?? true;
            download.IsInitialized = (bool?)data.Attribute("IsInitialized") ?? false;
            download.Path = (string)data.Attribute("Path") ?? "";
            download.DestinationFolder = (string)data.Attribute("DestinationFolder") ?? "";
            download.DestinationPath = (string)data.Attribute("DestinationPath") ?? "";
            download.Description = (string)data.Attribute("Description") ?? "";
            download.Size = (long?)data.Attribute("Size") ?? 0;
            download.FileName = (string)data.Attribute("FileName") ?? "";
            download.Position = (int?)data.Attribute("Position") ?? 0;
            download.ChunkSize = (int?)data.Attribute("ChunkSize") ?? 0;
            download.DownloadedAmount = (long?)data.Attribute("DownloadedAmount") ?? 0;
            download.DateCreated = (DateTime?)data.Attribute("DateCreated") ?? DateTime.Now;
            download.DateCompleted = (DateTime?)data.Attribute("DateCompleted") ?? DateTime.Now;
            download.TimeElapsed = (TimeSpan?)data.Attribute("TimeElapsed") ?? new TimeSpan(0);

            download.ParentGUID = _pluginGUID;

            DownloadStatuses downloadStatus;
            Enum.TryParse((string)data.Attribute("Status") ?? "", out downloadStatus);
            download.Status = downloadStatus;

            download.Segments.Clear();
            XElement segmentsElement = XmlUtils.GetDecendant(data, "Segments");
            foreach (XElement segmentElement in segmentsElement.Descendants("Segment"))
            {
                DownloadSegment downloadSegment = new DownloadSegment();

                downloadSegment.StartPosition = (long?)segmentElement.Attribute("StartPosition") ?? 0;
                downloadSegment.CurrentPosition = (long?)segmentElement.Attribute("CurrentPosition") ?? 0;
                downloadSegment.EndPosition = (long?)segmentElement.Attribute("EndPosition") ?? 0;

                download.Segments.Add(downloadSegment);
            }
        }
    }
}
